library(tidyverse)
library(ggplot2)
library(scales)SOK-2302 Seminar - klima
Introduksjon
I denne oppgaven skal vi se på data knyttet til klimaendringer. Datamaterialet kommer i fra National Oceanic and Atmospheric Administration (NOAA), som er USA:s tilsvarighet til meteorologisk institutt. NOAA har beregnet avvik fra “normalen” (gjenomsnittet i tidsperioden 1970 - 2000) for hvert år og måned i perioden 1850 - 2025. Dere finner datamaterialet her. Dere finner informasjon om innholdet i de ulike filene i ReadMe-filen.
Navnen på datafilene gir informasjon om hva filene innholder. For eksempel innholder filen “aravg.ann.land.00N.30N.v6.0.0.202508.asc” årlig informasjon for avvik i temperaturen over land (landoverflaten) fra ekvatorn (00N) til den 30. breddegraden. Filen inneholder data fram til august i 2025. Filen “aravg.ann.ocean.00N.30N.v6.0.0.202508.asc” har samme informasjon for temperaturen over havet, og “aravg.ann.land_ocean.00N.30N.v6.0.0.202508.asc” inneholder informasjon om totale temperaturavvik (ved overflaten).
Lattituder: * 90S-90N: Hele jorden * 00N - 90N: Fra ekvatorn til nordpolen (nordlig hemisfere) * 90S-00N: Fra sydpolen til ekvatorn (sydlig hemisfere) * 20S - 20N: Tropikene * 60N - 90N: Arktis * 90S - 60S: Antarktis
Når denne oppgaven ble laget, var den amerikanske staten stengt og hjemmesiden ser derfor litt rar ut. Det går likevel å hente data fra siden.
Det er fritt fram å bruke KI til å løse oppgavene, men se til at du har en forståelse for koden som KI lager. Det er ditt ansvar å se til at koden er riktig!
Oppgave 1 - Enkel grafisk illustrasjon av globale temperaturavvik i perioden 1850 - 2025
I denne oppgaven skal vi se på hvordan avviket i temperatur i havet og på land har varierer globalt sett fra år til år.
- Hent data for globale månedlige temperaturavvik for hav og land
- Lag en ny data frame med år, måned, og temperaturavvik
- Beregn gjennomsnittligt måntlig avvik i temperaturen og lag en ny variabel som inneholder denne informasjonen.
- Lag en graf som viser avvik fra normalen (Temperature anomaly) for hvert år i tidsperioden 1850-2025. Y-akselen skal vise avvik, X-akselen skal vise måneder. Bruk en linje-graf der enhvert år har en egen linje.
- Legg in svart, litt tykkere linje som viser gjennomsnittlig avvik fra normalen i perioden.
- Hva kan du utlese fra denne konklusjonen om global oppvarming?
Oppgave 2 - En litt mer lesbar graf
Som følge av det store tidsrommet er det vanskelig å få et bilde av utvikling over tid i den enkle grafen. I denne oppgaven skal vi derfor prøve å gjøre ting litt mere oversiktlig.
- Lag en graf der alle år fram til og med 2015 har en grå farge og er litt tynnere, mens temperaturavvikene i perioden 2015-2025 har ulike farger. Behold legenden for årene 2015 - 2025, fjern legenden for årene før.
- Hvilke konklusjoner kan vi trekke fra denne grafen i henhold til global oppvarming?
Oppgave 3 - Trender over tid i ulike regioner
I denne oppgaven skal vi se på temperaturavvik i ulike regioner i verden. Med regioner avses her ulike lattitude-bånd på jorden: Hele jorden, nordlige halvkulen, sørlige halvkulen, tropikkene, arktis, og antarktis. For å kunne sammenligne utviklingen i de ulike regionene bruker vi gjennomsnittlige avvik. Mer presist bruker vi et rullende 5-års gjennomsnitt på avvikene. Dataene hentes akkurat som før fra NOAA, men siden vi ønsker å sammenligne ulike regioner må vi bruke flere datafiler. I oppgaven under ser vi på overflate-temperaturen i havet og på land tatt sammen. Du kan selv prøve å endre koden slik at du ser på hav og land separat.
- Kjør koden
- Hvordan skal vi tolke innholdet i grafen?
# Packer som trengs
library(tidyverse)
library(zoo) # for å beregne rullende gjennomsnitt
library(lubridate)
# ---- PARAMETRER ----
# Version / date tag i NOAA fil-navn. bytt ut hvis NOAA har nyere filer.
version_tag <- "v6.0.0.202508"
# Variabel som skal brukes (valg av data-fil): "land_ocean", "land", or "ocean"
varname <- "land_ocean"
# Latittude bånd som skal sammenlignes (southLimit.northLimit)
bands <- c(
"90S.90N", # Globalt
"00N.90N", # Den nordlige halvkule
"90S.00N", # Den sørlige halvkule
"60N.90N", # Arktis
"90S.60S", # Antarktis
"20S.20N" # Tropikene
)
# Output
base_url <- "https://www.ncei.noaa.gov/data/noaa-global-surface-temperature/v6/access/timeseries"
# Rullende vindu for smoothing (år)
smooth_yrs <- 5
# ---- FUNKTIONER ----
read_noaa_aravg <- function(band, var = varname, version = version_tag) {
# Lag filenavn og url
fname <- sprintf("aravg.mon.%s.%s.%s.asc", var, band, version)
url <- paste(base_url, fname, sep = "/")
# les tabell (NOAA ascii: first cols year, month, anomaly, ...; comment lines start with #)
df <- read.table(url, header = FALSE, comment.char = "#", stringsAsFactors = FALSE)
colnames(df)[1:3] <- c("year", "month", "anomaly")
df <- df %>%
select(year, month, anomaly) %>%
mutate(year = as.integer(year),
month = as.integer(month),
anomaly = as.numeric(anomaly),
band = band)
return(df)
}
# ---- LAST INN DATA OG KOMBINER DATAKILDER ----
all_monthly <- map_df(bands, ~ read_noaa_aravg(.x))
# ---- Avvik er i Kelvin (K). Dette er lik °C for forskjeller. Vi behåndler dem som °C ----
# ---- ÅRLIGE GJENNOMSNITT ----
annual <- all_monthly %>%
group_by(band, year) %>%
summarise(
n_months = sum(!is.na(anomaly)),
annual_anom = ifelse(n_months >= 10, mean(anomaly, na.rm = TRUE), NA_real_),
.groups = "drop"
) %>%
filter(!is.na(annual_anom))
# ---- BASENIVÅ (1971-2000) ----
# Månedlig basenivå per måned og region
baseline_monthly <- all_monthly %>%
filter(year >= 1971, year <= 2000) %>%
group_by(band, month) %>%
summarise(clim = mean(anomaly, na.rm = TRUE), .groups = "drop")
# Årlig basenivå (gjennomsnitt av 12 månedlige klimaverdier) per region:
baseline_yr_mean <- baseline_monthly %>%
group_by(band) %>%
summarise(baseline_mean = mean(clim, na.rm = TRUE), .groups = "drop")
# Substraher årlig gjennomsnittlig for basenivået (1971-2000) slik at avvikene er eksplisitt relativt til dette basenivået:
annual <- annual %>%
left_join(baseline_yr_mean, by = "band") %>%
mutate(annual_anom_clim = annual_anom - baseline_mean) # Dette skal være approksimativt lik orginale anomalier i datamaterialet men sikkerstiller et eksplisitt basenivå
# ---- SMOOTHING (rullende gjennomsnitt) ----
# Konverter til tidsserie og beregne rullende gjennomsnitt (år)
annual <- annual %>%
arrange(band, year) %>%
group_by(band) %>%
mutate(
roll_n = rollapply(annual_anom_clim, width = smooth_yrs, FUN = mean, align = "center", fill = NA, na.rm = TRUE),
decade = year / 10
) %>%
ungroup()library(ggplot2)
# Palette for regions
region_colors <- c(
"Globalt" = "black",
"Nordlige halvkulen" = "#8856a7",
"Sørlige halvkulen" = "#7fcdbb",
"Arktis" = "red",
"Antarktis" = "#2c7fb8",
"Tropikkene" = "#fed976"
)
# Mappe region-koder til fine labels
band_labels <- tribble(
~band, ~label,
"90S.90N", "Globalt",
"00N.90N", "Nordlige halvkulen",
"90S.00N", "Sørlige halvkulen",
"60N.90N", "Arktis",
"90S.60S", "Antarktis",
"20S.20N", "Tropikkene"
)
plot_df <- annual %>% left_join(band_labels, by = "band")
# Graf
p <- ggplot(plot_df, aes(x = year)) +
geom_line(aes(y = annual_anom_clim, group = band), color = "grey70", alpha = 0.4) +
geom_line(aes(y = roll_n, color = label), size = 1.1, na.rm = TRUE) +
geom_hline(yintercept = 0, linetype = "dashed", color = "black") +
labs(
title = "Årlige temperaturavvik (relativt til 1971–2000)",
subtitle = paste0(smooth_yrs, "-års løpende gjennomsnitt; avikk i K (ekvivalent til °C for forskjeller)"),
x = "År",
y = "Temperaturavvik(°C)",
color = "Region"
) +
scale_x_continuous(breaks = seq(1850, 2030, by = 20)) +
theme_minimal(base_size = 12) +
theme(legend.position = "bottom")
my_colors <- c("black","#8856a7", "#7fcdbb", "red", "#2c7fb8", "#fed976")
names(my_colors) <- band_labels$label
p <- p + scale_color_manual(values = my_colors)Interaktiv plot
library(dplyr)
library(ggplot2)
library(plotly)
library(htmlwidgets)
# Beregne sikkre begrensninger for 7 (5% buffer) (ikke sikkert at dette er strikt nødvendig)
ymin <- min(plot_df$annual_anom_clim, plot_df$roll_n, na.rm = TRUE)
ymax <- max(plot_df$annual_anom_clim, plot_df$roll_n, na.rm = TRUE)
pad <- 0.05 * (ymax - ymin + 1e-9)
ymin <- ymin - pad; ymax <- ymax + pad
# Bestem rekkefølgen for de ulike regionene
region_order <- c("60N.90N","00N.90N","20S.20N","90S.00N","90S.60S", "90S.90N")
plot_df <- plot_df %>%
mutate(band = factor(band, levels = region_order))
# Lag en "desired label order" som tilsvarer region_order
desired_label_order <- band_labels$label[match(region_order, band_labels$band)]
plot_df <- plot_df %>%
mutate(label = factor(label, levels = desired_label_order)) %>%
# arrange so ggplot draws traces in the same order as the factor levels
arrange(label, year)
# Bestem farger
my_colors <- c("red", "#8856a7", "#fed976", "#7fcdbb","#2c7fb8", "black")
names(my_colors) <- desired_label_order
p <- ggplot(plot_df, aes(x = year)) +
# background thin lines: group by label so each region becomes one trace
geom_line(aes(y = annual_anom_clim, group = label),
color = "grey70", alpha = 0.4) +
# smoothed lines: group & color by label; put tooltip inside aes()
geom_line(aes(y = roll_n, color = label, group = label,
text = paste0(
"Region: ", label, "<br>",
"År: ", year, "<br>",
"Avvik: ", ifelse(is.na(roll_n), "NA",
paste0(round(roll_n, 3), " °C"))
)),
size = 1.1, na.rm = TRUE) +
geom_hline(yintercept = 0, linetype = "dashed") +
labs(title = "Årlige temperaturavvik (relativt til 1971–2000)",
subtitle = paste0(smooth_yrs, "-års løpende gjennomsnitt; avvik i K (ekvivalent til °C)"),
x = "År", y = "Temperaturavvik (°C)", color = "Region") +
scale_x_continuous(breaks = seq(1850, 2030, by = 20)) +
theme_minimal(base_size = 12) +
theme(legend.position = "bottom")
p <- p + scale_color_manual(values = my_colors)
# convert to plotly, use only the text tooltip, and set y axis range explicitly
gg_region <- ggplotly(p, tooltip = "text") %>%
layout(hovermode = "x unified",
#height = 16 * 250,
yaxis = list(range = c(ymin, ymax))) %>%
config(displayModeBar = TRUE)
# JavaScript: add/update vertical line at clicked x
js <- "
function(el, x) {
var plot = el;
plot.on('plotly_click', function(data) {
if(!data || !data.points || data.points.length === 0) return;
var xval = data.points[0].x;
var vline = {
type: 'line',
x0: xval, x1: xval,
y0: 0, y1: 1,
xref: 'x', yref: 'paper',
line: {color: 'black', width: 1.5, dash: 'dot'}
};
var shapes = (plot.layout.shapes || []).filter(function(s){ return s.name !== 'click_vline'; });
vline.name = 'click_vline';
shapes.push(vline);
Plotly.relayout(plot, {'shapes': shapes});
});
}
"
gg_region <- onRender(gg_region, js)
gg_regionOppgave 4
- Gjør om oppgave 3, men sammenlign temperatur for hav og land (globalt)
# Packer som trengs
library(tidyverse)
library(zoo) # for å beregne rullende gjennomsnitt
library(lubridate)
# ---- PARAMETRER ----
# Version / date tag i NOAA fil-navn. bytt ut hvis NOAA har nyere filer.
version_tag <- "v6.0.0.202508"
# Variabel som skal brukes (valg av data-fil): "land_ocean", "land", or "ocean"
varname <- "90S.90N"
# Latittude bånd som skal sammenlignes (southLimit.northLimit)
type <- c(
"land", # land
"ocean" # hav
)
# Output
base_url <- "https://www.ncei.noaa.gov/data/noaa-global-surface-temperature/v6/access/timeseries"
# Rullende vindu for smoothing (år)
smooth_yrs <- 5
# ---- FUNKTIONER ----
read_noaa_aravg <- function(type, var = varname, version = version_tag) {
# Lag filenavn og url
fname <- sprintf("aravg.mon.%s.%s.%s.asc", type, var, version)
url <- paste(base_url, fname, sep = "/")
# les tabell (NOAA ascii: first cols year, month, anomaly, ...; comment lines start with #)
df <- read.table(url, header = FALSE, comment.char = "#", stringsAsFactors = FALSE)
colnames(df)[1:3] <- c("year", "month", "anomaly")
df <- df %>%
select(year, month, anomaly) %>%
mutate(year = as.integer(year),
month = as.integer(month),
anomaly = as.numeric(anomaly),
type = type)
return(df)
}
# ---- LAST INN DATA OG KOMBINER DATAKILDER ----
all_monthly <- map_df(type, ~ read_noaa_aravg(.x))
# ---- ÅRLIGE GJENNOMSNITT ----
annual <- all_monthly %>%
group_by(type, year) %>%
summarise(
n_months = sum(!is.na(anomaly)),
annual_anom = ifelse(n_months >= 10, mean(anomaly, na.rm = TRUE), NA_real_),
.groups = "drop"
) %>%
filter(!is.na(annual_anom))
# ---- BASENIVÅ (1971-2000) ----
# Månedlig basenivå per måned og region
baseline_monthly <- all_monthly %>%
filter(year >= 1971, year <= 2000) %>%
group_by(type, month) %>%
summarise(clim = mean(anomaly, na.rm = TRUE), .groups = "drop")
# Årlig basenivå (gjennomsnitt av 12 månedlige klimaverdier) per region:
baseline_yr_mean <- baseline_monthly %>%
group_by(type) %>%
summarise(baseline_mean = mean(clim, na.rm = TRUE), .groups = "drop")
# Substraher årlig gjennomsnittlig for basenivået (1971-2000) slik at avvikene er eksplisitt relativt til dette basenivået:
annual <- annual %>%
left_join(baseline_yr_mean, by = "type") %>%
mutate(annual_anom_clim = annual_anom - baseline_mean) # Dette skal være approksimativt lik orginale anomalier i datamaterialet men sikkerstiller et eksplisitt basenivå
# ---- SMOOTHING (rullende gjennomsnitt) ----
# Konverter til tidsserie og beregne rullende gjennomsnitt (år)
annual <- annual %>%
arrange(type, year) %>%
group_by(type) %>%
mutate(
roll_n = rollapply(annual_anom_clim, width = smooth_yrs, FUN = mean, align = "center", fill = NA, na.rm = TRUE),
decade = year / 10
) %>%
ungroup()library(ggplot2)
# Palette for regions
type_colors <- c(
"Hav" = "#2c7fb8",
"Land" = "#7fcdbb"
)
# Mappe region-koder til fine labels
type_labels <- tribble(
~type, ~label,
"ocean", "Hav",
"land", "Land"
)
plot_df <- annual %>% left_join(type_labels, by = "type")
# Graf
p_type <- ggplot(plot_df, aes(x = year)) +
geom_line(aes(y = annual_anom_clim, group = type), color = "grey70", alpha = 0.4) +
geom_line(aes(y = roll_n, color = label), size = 1.1, na.rm = TRUE) +
geom_hline(yintercept = 0, linetype = "dashed", color = "black") +
labs(
title = "Årlige temperaturavvik (relativt til 1971–2000)",
subtitle = paste0(smooth_yrs, "-års løpende gjennomsnitt; avikk i K (ekvivalent til °C for forskjeller)"),
x = "År",
y = "Temperaturavvik(°C)",
color = "Type"
) +
scale_x_continuous(breaks = seq(1850, 2030, by = 20)) +
theme_minimal(base_size = 12) +
theme(legend.position = "bottom")
my_colors <- c("#2c7fb8", "#7fcdbb")
names(my_colors) <- type_labels$label
p_type <- p_type + scale_color_manual(values = my_colors)
print(p_type)